/**
 * 
 */
package com.hsnr.findyourbuddy;

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.apache.commons.io.IOUtils;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.map.JsonMappingException;

import android.content.ContentResolver;
import android.content.Context;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.preference.PreferenceManager;
import android.provider.ContactsContract;
import android.util.Log;

import com.hsnr.findyourbuddy.SystemException.ErrorType;

/**
 * @author Hendric
 * 
 */
public class CommunicationHandler {

    String serverName;
    int port;

    Socket client;
    BufferedReader input = null;
    PrintWriter output = null;
    Response res = null;
    public static String TAG = "FindYourBuddy";

    /**
     * @throws IOException
     * 
     */
    public CommunicationHandler(String ip, int port) throws IOException {
        this.serverName = ip;
        this.port = port;
        init();
    }

    private void init() throws IOException {
        try {
            Log.i(TAG, "Verbinde zu " + serverName + " auf port " + port);
            client = new Socket(InetAddress.getByName(serverName), port);
            client.setSoTimeout(20000);
            // client.setKeepAlive(true);
            input = new BufferedReader(new InputStreamReader(client.getInputStream()));
            output = new PrintWriter(new BufferedOutputStream(client.getOutputStream()));
            Log.i(TAG, "Verbunden!");

            if (input != null && output != null) {
                Log.i(TAG, "Streams initialisiert! ");
            }

        } catch (UnknownHostException e) {
            Log.e(TAG, e.getMessage());
        } catch (IOException e) {
            Log.e(TAG, e.getMessage());
            throw e;
        }
    }

    protected void sendBroadcastRequest(Context context) throws IOException {
        try {
            // Senden der Anfrage (Request)
            Log.i(TAG, "Sende Broadcastanfrage");
            final SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
            final String ownMobile = sharedPrefs.getString("prefMobile", null);
            String request = new BroadcastRequest(ownMobile).toJSON();
            if (output != null && !client.isClosed()) {
                output.println(request);
                output.flush();
                Log.i(TAG, "Bereit zum Empfangen!");
            } else {
                throw new IOException("Outputstream nicht initialisiert!");
            }
        } catch (JsonParseException e) {
            e.printStackTrace();
        } catch (JsonMappingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
            throw e;
        }

    }

    protected void sendContactRequest(Context context) throws IOException {
        try {
            // Senden der Anfrage (Request)
            Log.i(TAG, "Sende Contactanfrage");
            String request1 = new Request(ConversationTypes.CT_CONTACT).toJSON();
            final SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
            final String ownMobile = sharedPrefs.getString("prefMobile", null);
            if (ownMobile == null) {
                return;
            }
            ContactRequest cr = new ContactRequest(ownMobile);
            if (cr.getMobile() != null) {
                cr.setContacts(getContactList(context));
                String request2 = cr.toJSON();
                if (output != null && !client.isClosed()) {
                    output.println(request1);
                    output.flush();
                    output.println(request2);
                    Log.i(TAG, "[REQUEST] " + request2);
                    output.flush();
                    Log.i(TAG, "Bereit zum Empfangen!");
                } else {
                    throw new IOException("Outputstream nicht initialisiert!");
                }
            }
        } catch (JsonParseException e) {
            e.printStackTrace();
        } catch (JsonMappingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
            throw e;
        }

    }

    protected void sendSingleRequest(Context context, String mobilNr) throws IOException {
        try {
            // Senden der Anfrage (Request)
            Log.i(TAG, "Sende Registrierungsanfrage");
            final SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
            final String ownMobile = sharedPrefs.getString("prefMobile", null);
            String request1 = new Request(ConversationTypes.CT_SINGLE).toJSON();
            SingleRequest cr = new SingleRequest(ownMobile);
            String request = cr.toJSON();
            if (output != null && !client.isClosed()) {
                output.println(request1);
                output.flush();
                output.println(request);
                Log.i(TAG, "[REQUEST] " + request);
                output.flush();
                Log.i(TAG, "Bereit zum Empfangen!");
            } else {
                throw new IOException("Outputstream nicht initialisiert!");
            }
        } catch (JsonParseException e) {
            e.printStackTrace();
        } catch (JsonMappingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
            throw e;
        }

    }
    
    protected void sendCoordinates(Context context, String mobilNr, HashMap<String, String> coordinates)
            throws IOException {
        try {
            // Senden der Anfrage (Request)
            Log.i(TAG, "Sende Koordinaten");
            final SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
            final String ownMobile = sharedPrefs.getString("prefMobile", null);
            String request1 = new Request(ConversationTypes.CT_COORDINATES).toJSON();
            CoordinateRequest cr = new CoordinateRequest(ownMobile, coordinates);
            String request = cr.toJSON();
            if (cr.getCoordinates() != null) {
                if (output != null && !client.isClosed()) {
                    output.println(request1);
                    output.flush();
                    output.println(request);
                    Log.i(TAG, "[REQUEST] " + request);
                    output.flush();
                } else {
                    throw new IOException("Outputstream nicht initialisiert!");
                }
            } else {
                Log.i(TAG, "keine Koordinaten");
            }
        } catch (JsonParseException e) {
            e.printStackTrace();
        } catch (JsonMappingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
            throw e;
        } finally {

        }

    }

    private ArrayList<Contact> getContactList(Context c) {
        ArrayList<Contact> contacts = new ArrayList<Contact>();
        ContentResolver cr = c.getContentResolver();
        Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
        if (cur.getCount() > 0) {
            while (cur.moveToNext()) {
                String id = cur.getString(cur.getColumnIndex(ContactsContract.Contacts._ID));
                // String name =
                // cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
                if (Integer.parseInt(cur.getString(cur.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))) > 0) {
                    Cursor pCur = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,
                            ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?", new String[] { id }, null);
                    while (pCur.moveToNext()) {
                        String phoneNo = pCur.getString(pCur
                                .getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
                        Contact co = new Contact();
                        co.setMobilfunknummer(phoneNo);
                        contacts.add(co);
                    }
                    pCur.close();
                }
            }
        }
        return contacts;
    }

    public void close() {
        IOUtils.closeQuietly(input);
        IOUtils.closeQuietly(output);
        IOUtils.closeQuietly(client);
    }

    @SuppressWarnings("rawtypes")
    protected Response receiveResponse(Class type) throws IOException {

        Log.i(TAG, "Empfange Response");
        List<String> lines = new ArrayList<String>();
        String line;
        while ((line = input.readLine()) != null) {
            lines.add(line);
        }

        Log.i(TAG, "Empfangen...");

        StringBuilder sb = new StringBuilder();
        for (String s : lines) {
            Log.i(TAG, "[Response]:" + s);
            sb.append(s);
        }
        try {
            if (sb.length() != 0) {
                if (type == BroadcastResponse.class)
                    res = BroadcastResponse.fromJSON(sb.toString());
                else if (type == ContactResponse.class)
                    res = ContactResponse.fromJSON(sb.toString());
                else
                    return null;
            } else {
                Log.e(TAG, "Keine Response empfangen");
                throw new SystemException(ErrorType.NO_RESPONSE_RECEIVED);
            }

        } catch (JsonParseException e) {
            e.printStackTrace();
        } catch (JsonMappingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        Log.i(TAG, "Response empfangen");
        if (res == null) {
            throw new SystemException(ErrorType.NO_RESPONSE_RECEIVED);
        }
        return res;
    }

    
}
